//
// Created by Administrator on 2021/4/11.
//

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "iostream"
#include "fstream"
#include "video_learning.h"

int main()
{
    //创建Mat类（初始化赋值）
    Video video;
    video.read_video();
    cv::Mat a;//创建一个名为a的矩阵头
    a = cv::imread("D:\\pictures\\lena.jpg");// 向a中赋值图像数据，矩阵指针指向像素数据
    cv::Mat b=a; //复制矩阵头，并命名为b a,b的矩阵指针指向相同的像素数据，b变，a也变
    cv::Mat B(a); //等价于 B = a
    cv::Mat a_clone = a.clone(); //复制a，但彼此互相不受影响，改变a_clone不会改变a

    // 声明一个指定类型的Mat类（未初始化赋值）
    cv::Mat A = cv::Mat_<double>(3, 3); //创建一个3*3的矩阵用于存放double类型的数据

    // 通过opencv数据类型创建Mat类（未初始化赋值）
    cv::Mat c(640, 480, CV_8UC3);//创建一个640*480的3通道矩阵用于存放彩色图像
    cv::Mat d(3, 3, CV_8UC1);//创建一个3*3的1通道矩阵用于存放灰度图像
    cv::Mat e(3, 3, CV_8U); //创建单通道矩阵，c1标识可以省略

    //Mat类的构造
    /*
     * （1）利用默认构造函数（常用于存储读取图像数据和某个函数运算的输出结果）
     *      cv::Mat::Mat();
     *      即直接声明cv::Mat a; a就是利用默认构造函数赋值的。在后续给变量赋值时会自动判断矩阵的类型和大小
     *  (2) 根据输入矩阵尺寸和类型构造Mat类
     *      cv::Mat::Mat( int rows,
     *                    int cols,
     *                    int type
     *                    )
     *       rows: 构造矩阵的行数
     *       cols：矩阵列数
     *       type: 矩阵存储的数据类型（例如CV_8UC1,CV_8UC3,...CV_8UC(n) n为通道数，最多512）
     *       例如： cv::Mat c(640, 480, CV_8UC3);//创建一个640*480的3通道矩阵用于存放彩色图像
     *
     *       cv::Mat::Mat( Size size(),
     *                     int  type
     *                    )
     *        size: 二维数组变量尺寸，通过Size（cols,rows）进行赋值
     *        例如：cv::Mat a(Size(480, 640), CV_8UC1);
     *   (3) 根据已有矩阵构造Mat类
     *       cv::Mat::Mat(const Mat &m)
     *       m: 已经构建完成的Mat类矩阵数据
     *       例如：cv::Mat a;//创建一个名为a的矩阵头
                  a = cv::imread("D:\\pictures\\lena.jpg");// 向a中赋值图像数据，矩阵指针指向像素数据
                  cv::Mat B(a); //等价于 B = a，
                  //B 就是利用已有矩阵构造
             构造已有Mat类的子类
             cv::Mat::Mat(const Mat &m,
                          const Range &rowRange,
                          const Range &colRange=Range::all()
                          )
             rowRange:在已有矩阵中需要截取的行数范围，是一个Range变量，例如从第五行到第六行Range(5, 6)
             colRange:在已有矩阵中需要截取的列数范围，是一个Range变量，例如从第五列到第六列Range(5, 6)，当不输入任何值时，表示所有列都截取
             例如： cv::Mat b(a, Range(2, 5), Range(5, 6)); //从a中截取部分数据构造b
     *
     *
     */

    //Mat类的赋值
    /*
     * 构造完Mat类后，变量没有数据，需要赋值
     * (1) 构造时赋值
     *  cv::Mat::Mat( int rows,
     *                int cols,
     *                int type,
     *                const Scalar &s
     *               )
     *   s: 给矩阵中每个像素赋值的参数变量 例如Scalar(0, 0, 255)
     *   例如：cv::Mat a(2, 2, CV_8UC3, cv::Scalar(0, 0, 255));//创建一个3通道的矩阵，每个像素值为0,0,255
     *        cv::Mat b(2, 2, CV_8UC1, cv::Scalar(255));//创建一个1通道的矩阵，每个像素值为255
     * (2) 利用枚举法赋值（将矩阵中的所有元素一一列举），并用数据流的形式赋值给Mat类,输入数据个数要和矩阵元素个数相同
     *   cv::Mat a = (cv::Mat_<int>(3,3) << 1,2,3,4,5,6,7,8,9);
     * (3) 利用循环法赋值
     *   cv::Mat c = cv::Mat_<int>(3, 3);
     *   for (int i=0; i<c.rows; i++)
     *   {
     *      for(int j=0; j<c.cols; j++)
     *      {
     *         c.at<int>(i,j) = i+j;
     *      }
     *   }
     * (4) 类方法赋值
     *   cv::Mat a=cv::Mat::eye(3, 3, CV_8UC1);
     *   cv::Mat b=(cv::Mat_<int>(1, 3) << 1,2,3);
     *   cv::Mat c=cv::Mat::diag(b);
     *   cv::Mat d=cv::Mat::ones(3, 3, CV_8UC1);
     *   cv::Mat e=cv::Mat::zeros(3, 3, CV_8UC1);
     *   eye():构建一个单位矩阵
     *   diag()：构建一个对角矩阵，其参数必须是Mat类型的一维变量，用于存放对角元素的数值
     *   ones()：构建一个全为1的矩阵
     *   zeros()：构建一个全为0的矩阵
     * (5) 利用数组赋值
     *   float a[8]={1,2,3,4,5,6,7,8};
     *   cv::Mat b=cv::Mat(2, 4, CV_32FC2,a);
     */

    //Mat类的加减乘除运算
    //当两个Mat变量进行加减运算时，必须保证两个矩阵中的数据类型是相同的
    cv::Mat C = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
    cv::Mat D = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
    cv::Mat E = (cv::Mat_<double>(3, 3) << 1.0, 2.1, 3.2, 4.0, 5.1, 6.2, 2, 2, 2);
    cv::Mat F = (cv::Mat_<double>(3, 3) << 1.0, 2.1, 3.2, 4.0, 5.1, 6.2, 2, 2, 2);
    cv::Mat f, g, h, i, j;
    f = C+D;
    g = E-F;
    h = C*2;
    i = F/2.0;
    j = C-1;
    std::cout<<"C:"<<std::endl<<C<<std::endl<<"D:"<<std::endl<<D<<std::endl
             <<"E:"<<std::endl<<E<<std::endl<<"F:"<<std::endl<<F<<std::endl
             <<"f:C+D"<<std::endl<<f<<std::endl<<"g:E-F"<<std::endl<<g<<std::endl
             <<"h:C*2"<<std::endl<<h<<std::endl<<"i:F/2.0"<<std::endl<<i<<std::endl
             <<"j:C-1"<<std::endl<<j<<std::endl;
    //两个Mat类矩阵的乘法运算
    cv::Mat k,m;
    double l;
    //矩阵乘法
    k = E*F;
    //矩阵内积A=[a1,a2,a3],B=[b1,b2,b3], A.dot(B)=a1*b1+a2*b2+a3*b3
    l = C.dot(D);
    //矩阵对应位乘积
    m = C.mul(D);

    //Mat类元素的读取

    /*
     *  //通过at方法读取Mat类矩阵元素
        at方法读取Mat类单通道矩阵元素
        cv::Mat a = (cv::Mat_<uchar>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
        int value = (int)a.at<uchar>(0, 0);

        at方法读取Mat类多通道矩阵元素
        cv::Mat b(3, 4, CV_8UC3, cv::scalar(0, 0, 1));
        cv::Vec3b vc3 = b.at<cv::Vec3b>(0, 0);
        int first = (int)vc3[0];
        int second = (int)vc3[1];
        int third = (int)vc3[2];

        //通过指针ptr读取Mat类矩阵中的元素
        指针ptr读取Mat类矩阵元素
        cv::Mat b(3, 4, CV_8UC3, cv::scalar(0, 0, 1));
        for(int i=0; i<b.rows; i++)
        {
           uchar *ptr = b.ptr<uchar>(i);
           for(int j=0; j<b.cols*b.channels(); j++)
           {
              std::cout<<(int)ptr[j]<<std::endl;
           }
        }
        当我们能够确定需要访问的数据时，可以直接通过给出行数和指针后移的位数进行访问
        例如当读取第二行中第三个数据时，可以用a.ptr<uchar>(1)[2]来直接访问

        //通过迭代器访问Mat类矩阵中的元素
        cv::MatIterator_<uchar> it = a.begin<uchar>();
        cv::MatIterator_<ucahr> it_end = a.end<uchar>();
        for(int i= 0; it!=it_end; it++)
        {
          cout<<(int)(*it)<<"";
          if((++i%a.cols)==0)
          {
            cout<<endl;
          }
        }


    */

    /*
     * ----------图像的读取与显示------------
     *
     * 图像读取函数imread------
     * imread()函数原型
     * cv::Mat cv::imread(const String &filename,
     *                    int flags=IMREAD_COLOR
     *                    )
     * flags:读取图像的标志，默认为彩色（-1：按图像原样读取 0：图像转换成灰度图后读取， 1：图像转换成3通道BGR彩色图像）
     *
     * 图像窗口函数namedWindow-----
     * namedWindow函数原型
     * void cv::namedWindow(const String &winname,
     *                      int flags = WINDOW_AUTOSIZE
     *                     )
     * winname:窗口名称
     * flags：窗口属性设置标志
     *
     * 图像显示函数imshow
     * imshow()函数原型
     * void cv::imshow(const String &winname,
     *                 InputArray mat
     *                 )
     * mat: 要显示的图像矩阵
     */

    std::cout<<"k:E*F"<<std::endl<<k<<std::endl<<"m:C.mul(D)"<<std::endl<<m<<std::endl
             <<"l:C.dot(D)"<<std::endl<<l<<std::endl;

    cv::namedWindow("first_picture", cv::WINDOW_AUTOSIZE);
    cv::imshow("first_picture", b);
    cv::waitKey();
    cv::destroyWindow("first_picture");
    return 0;

}